package palms.security;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.io.UnsupportedEncodingException;
import java.net.Socket;
import java.security.InvalidKeyException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.KeyGenerator;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SealedObject;
import javax.crypto.spec.SecretKeySpec;

import palms.exceptions.ErrorMessage;
import palms.exceptions.InvalidClassMessage;
import palms.exceptions.InvalidTicketMessage;
import palms.exceptions.InvalidUserMessage;

public class PalmsSecurityManager {
	
	
	public static SecretKeySpec getKeyFromString(String s) throws NoSuchAlgorithmException, UnsupportedEncodingException{
		MessageDigest md = MessageDigest.getInstance("SHA1");
		byte[] bkey = s.getBytes("UTF8");
		bkey = md.digest(bkey);
		return new SecretKeySpec(bkey, 0, 16, "AES");
	}
	
	
	public static Cipher getCipherForKey(SecretKeySpec k) throws InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException{
		Cipher c = Cipher.getInstance("AES");
		c.init(Cipher.ENCRYPT_MODE, k);
		return c;
	}
	
	
	public static SecretKeySpec getSessionKey() throws NoSuchAlgorithmException{
		return (SecretKeySpec) KeyGenerator.getInstance("AES").generateKey();
	}
	
	
	public static SealedObject SealObjectWithK(Object o, SecretKeySpec k) throws IllegalBlockSizeException, IOException, InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException{
		Cipher c = PalmsSecurityManager.getCipherForKey(k);
		return new SealedObject((Serializable) o, c);
	}
	
	public static Object DesealObjectWithK(SealedObject o, SecretKeySpec k) throws IllegalBlockSizeException, IOException, InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException, BadPaddingException, ClassNotFoundException{
		Cipher c = Cipher.getInstance("AES");
		c.init(Cipher.DECRYPT_MODE, k);
		return o.getObject(c);
	}
	
	public static void sendError(Socket s, ErrorMessage em) throws IOException{
		ObjectOutputStream oo = new ObjectOutputStream(s.getOutputStream());
		oo.writeObject(em);
	}
	
	public static void sendObjectTroughtSocket(Socket s, Serializable seo) throws IOException {
		ObjectOutputStream oo = new ObjectOutputStream(s.getOutputStream());
		oo.writeObject(seo);
	}
	
	public static Object receiveObjectTroughSocket(Socket s) throws IOException, ClassNotFoundException{	
		ObjectInputStream io = new ObjectInputStream(s.getInputStream());
		Object o = io.readObject();
		return o;
	}
	
	public static void throwCommException(Object o) throws InvalidClassMessage, InvalidUserMessage, InvalidTicketMessage{
		if (!(o instanceof ErrorMessage))
			throw new InvalidClassMessage();
		if (o instanceof InvalidClassMessage)
			throw (InvalidClassMessage) o;
		if (o instanceof InvalidUserMessage)
			throw (InvalidUserMessage) o;
		if (o instanceof InvalidTicketMessage)
			throw (InvalidTicketMessage) o;
	}
	
    public static String asHex (byte buf[]) {
    	StringBuffer strbuf = new StringBuffer(buf.length * 2);
    	int i;

    	for (i = 0; i < buf.length; i++) {
    		if (((int) buf[i] & 0xff) < 0x10)
    			strbuf.append("0");

    		strbuf.append(Long.toString((int) buf[i] & 0xff, 16));
    	}

    	return strbuf.toString();
    }
	
}
